<?php
/*
 * description：
 * author：wh
 * email：
 * createTime：{2021/11/08} {17:00} 
 */

namespace wanghua\general_utility_tools_php\pay\shouyinbaopay;


use wanghua\general_utility_tools_php\tool\Tools;

/**
 * 通联 - 收银宝统一支付
 *
 *  端口：443
 *
 *  接口地址：https://vsp.allinpay.com/apiweb/unitorder/pay
 *
 *  测试地址：https://syb-test.allinpay.com/apiweb/unitorder/pay
 *
* 使用场景：请求扫码支付的二维码串（支持支付宝、QQ钱包、云闪付),
 *  公众号JS支付（支付宝，微信，QQ钱包，云闪付）,微信小程序支付
 *
 * 通联 - 收银宝暂不支持微信h5支付(网页直接拉起微信支付)
 *
 * Class ShouYinBaoUnifyPay
 * @package app\index\pay\pay
 */
class ShouYinBaoUnifyPay
{

    public $order_id = '';//本系统交易订单号 必须
    public $price = 0;//支付金额  分  必须
    public $body = '';//商品名称 必须 可用商品名称
    public $remark = '';//备注
    public $openid = '';//微信openid 必须
    public $notify_url = '';//接收异步通知的url 必须
    public $front_url = '';//支付操作结果页面（通联主动跳转）

    /**
     * desc：h5支付
     * author：wh
     * @return mixed
     */
    function h5pay(){



        return Tools::set_res(500, '该平台不支持h5支付，请使用app调用微信小程序实现。');
    }

    /**
     * desc：通联 - 收银宝微信jsapi支付
     *
     * 开发文档doc: https://aipboss.allinpay.com/know/devhelp/main.php?pid=15#mid=88
     *
     * 备注：附录中交易方式决定各种交易场景，详情请查看附录
     *
     * author：wh
     * @param string $pay_domain 通联-收银宝支付域名
     * @param string $private_key 通联-收银宝商户私钥
     * @param string $cusid 在通联-收银宝后台注册分配的商户号
     * @param string $appid 在通联-收银宝后台注册分配的appid
     * @param string $version 版本号，默认 11
     * @param string $weixin_appid 使用方的微信appid
     * @return array 支付结果 payinfo用于微信jsapi的支付参数，直接使用即可
     */
    function wechatJsapiPay(string $pay_domain, string $private_key, string $cusid, string $appid, string $version, string $weixin_appid){
        //注释调的是非必须参数
        $params = array();
        $params["cusid"] = $cusid;
        $params["appid"] = $appid;
        $params["version"] = $version;
        //$params["orgid"] = '';
        $params["trxamt"] = $this->price;
        $params["reqsn"] = $this->order_id;
        $params["paytype"] = 'W02';
        $params["body"] = $this->body;
        $params["remark"] = $this->remark;
        //$params["validtime"] = 12;
        $params["acct"] = $this->openid;//jsapi时，填openid
        $params["notify_url"] = $this->notify_url;
        //$params["limit_pay"] = '';
        $params["sub_appid"] = $weixin_appid;
        //$params["subbranch"] = '';
        //$params["cusip"] = '';
        //$params["idno"] = '';
        //$params["truename"] = '';
        //$params["fqnum"] = '';
        $params["randomstr"] = Tools::rand_str();
        $params["signtype"] ='RSA';
        //支付完成跳转 必须为https协议地址，且不允许带参数
        $params["front_url"] = $this->front_url;//

        $params["sign"] = urlencode($this->Sign($params,$private_key));//签名
        $paramsStr = $this->ToUrlParams($params);

        $url = $pay_domain . "/apiweb/unitorder/pay";
        $rsp = $this->request($url, $paramsStr);

        if($rsp['code'] != 200){
            return Tools::set_res(500,'支付请求错误.'.$rsp['msg']);
        }

        $rspArray = json_decode($rsp['data'], true);
        if(strtolower($rspArray['retcode']) != 'success'){
            return Tools::set_res(500,'支付失败.');
        }

        if(!$this->validSign($rspArray)){
            return Tools::set_res(500,'验签失败.');
        }

        //验证交易状态
        if($rspArray['trxstatus'] !== '0000'){
            return Tools::set_res(500,'交易未成功.');
        }

        return Tools::set_res(200, 'ok',$rspArray);
    }


    /**
     * desc：jsapi支付对应的通知
     *
     *  {"acct":"ojEmk5lAXuEDVBPTqKM3N7jLnkmc","accttype":"99","appid":"00224060","chnlid":"205299480",
        "chnltrxid":"4200001173202111091438864430","cmid":"472485785","cusid":"553361048165HBG","cusorderid":"wx1636446415073835792",
        "fee":"0","initamt":"1","outtrxid":"wx1636446415073835792","paytime":"20211109162701",
        "sign":"AxjxzsvPo9nGVLHTZ9DtxsZcP9H+n8sdRFTlLjEa1929e/dyFmxd2ee88QuCgUBsUFLNsoNy++n41MrBbiK6Gzi3kLqPGU3qxRe7ZJLMKKLgrSgU
        Sc0w/mSq0HvaaF6W81WH2XaOzHACCQ4qd5bn0gMf97GwlByNgblivb0dJnA=",
        "signtype":"RSA","termauthno":"OTHERS","termrefnum":"4200001173202111091438864430","termtraceno":"0",
        "trxamt":"1","trxcode":"VSP501","trxdate":"20211109","trxid":"211109116606825752",
        "trxreserved":"参赛券购买","trxstatus":"0000"}
     *
     * author：wh
     * @return array
     */
    function jsapiNotify(){
        $params = array();
        //动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常
        foreach($_POST as $key=>$val) {
            $params[$key] = $val;
        }
        if(count($params)<1){//如果参数为空,则不进行处理
            return Tools::set_res(500, '未获取到参数',$params);
        }
        if(!$this->ValidSign($params)){//验签成功
            //此处进行业务逻辑处理
            return Tools::set_res(500, '签名校验失败',$params);
        }

        $tradeStatus = $params['trxstatus'];
        if(strtolower($tradeStatus) != '0000'){
            return Tools::set_res(500, '交易未成功',$params);
        }

        return Tools::set_res(200, '交易成功',$params);
    }



    /**
     * RSA签名
     *
     * 将参数数组签名
     */
    protected function Sign(array $array,string $private_key){
        ksort($array);
        $bufSignSrc = $this->ToUrlParams($array);
        $private_key = chunk_split($private_key , 64, "\n");
        $key = "-----BEGIN RSA PRIVATE KEY-----\n".wordwrap($private_key)."-----END RSA PRIVATE KEY-----";

        if(!openssl_sign($bufSignSrc, $signature, $key )){
            return '';
        }
        //加密后的内容通常含有特殊字符，需要编码转换下，在网络间通过url传输时要注意base64编码是否是url安全的
        $sign = base64_encode($signature);

        return $sign;

    }

    /**
     * desc：
     * author：wh
     * @param array $array
     * @return string
     */
    protected function ToUrlParams(array $array)
    {
        $buff = "";
        foreach ($array as $k => $v)
        {
            if($v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 校验签名
     * @param array 参数
     * @param unknown_type appkey
     */
    protected function ValidSign(array $array){
        $sign =$array['sign'];
        unset($array['sign']);
        ksort($array);
        $bufSignSrc = $this->ToUrlParams($array);
        //通联固定公钥
        $public_key='MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm9OV6zH5DYH/ZnAVYHscEELdCNfNTHGuBv1nYYEY9FrOzE0/4kLl9f7Y9dkWHlc2ocDwbrFSm0Vqz0q2rJPxXUYBCQl5yW3jzuKSXif7q1yOwkFVtJXvuhf5WRy+1X5FOFoMvS7538No0RpnLzmNi3ktmiqmhpcY/1pmt20FHQQIDAQAB';
        $public_key = chunk_split($public_key , 64, "\n");
        $key = "-----BEGIN PUBLIC KEY-----\n$public_key-----END PUBLIC KEY-----\n";
        $result= openssl_verify($bufSignSrc,base64_decode($sign), $key );
        return $result;
    }

    /**
     * desc：发送请求操作仅供参考,不为最佳实践
     * author：wh
     * @param $url
     * @param $params
     * @return array
     */
    protected function request($url,$params){
        $curl = curl_init();
        $this_header = array("content-type: application/x-www-form-urlencoded;charset=UTF-8");
        curl_setopt($curl,CURLOPT_HTTPHEADER,$this_header);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($curl, CURLOPT_TIMEOUT, 3);

        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);//如果不加验证,就设false,商户自行处理
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        $output = curl_exec($curl);

        // 显示错误信息
        if (curl_error($curl)) {
            //返回错误码
            return ['code' => curl_errno($curl), 'msg' => curl_error($curl)];
        } else {
            //关闭句柄
            curl_close($curl);
            // 返回的内容
            return ['code' => 200, 'msg' => 'ok', 'data' => $output];
        }
    }

}